package com.specificgroup.jira.plugin.acpro.servlet;

import com.atlassian.jira.security.PermissionManager;
import com.atlassian.jira.security.Permissions;
import com.atlassian.jira.util.json.JSONArray;
import com.atlassian.jira.util.json.JSONException;
import com.atlassian.jira.util.json.JSONObject;
import com.atlassian.seraph.auth.DefaultAuthenticator;
import com.opensymphony.user.User;
import com.specificgroup.jira.plugin.acpro.Constants;
import com.specificgroup.jira.plugin.acpro.mapping.*;
import com.specificgroup.jira.plugin.acpro.sync.Sync;
import com.specificgroup.jira.plugin.acpro.sync.Event;
import com.specificgroup.jira.plugin.acpro.model.Settings;
import com.specificgroup.jira.plugin.acpro.model.jira.JiraProjectComponent;
import com.specificgroup.jira.plugin.acpro.service.JiraAcproPluginJiraManager;
import com.specificgroup.jira.plugin.acpro.service.JiraAcproSettingsService;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.log4j.Logger;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;

/**
 * @author Ivan Holub
 */
public class AcproServlet extends HttpServlet {

    private static final String ACTION_USERS = "users";

    private static final String ACTION_ISSUE_TYPES = "issueTypes";

    private static final String ACTION_PRIORITIES = "priorities";

    private static final String ACTION_STATUSES = "statuses";

    private static final String ACTION_RESOLUTIONS = "resolutions";

    private static final String ACTION_PROJECT_COMPONENTS = "projectComponents";

    private static final String ACTION_PROJECT_VERSIONS = "projectVersions";

    private static final String ACTION_SETTINGS = "settings";

    private static final String ACTION_EVENTS = "events";

    private static final String PARAM_PROJECT_ID = "projectId";

    private static final String CONTENT_TYPE_JSON = "text/json";

    private static final String CONTENT_TYPE_XML = "text/xml";

    private Logger log = Logger.getLogger(getClass());

    private JiraAcproPluginJiraManager jiraAcproPluginJiraManager;

    private JiraAcproSettingsService jiraAcproSettingsService;

    private PermissionManager permissionManager;

    public AcproServlet(JiraAcproPluginJiraManager jiraAcproPluginJiraManager, JiraAcproSettingsService jiraAcproSettingsService, PermissionManager permissionManager) {
        this.jiraAcproPluginJiraManager = jiraAcproPluginJiraManager;
        this.jiraAcproSettingsService = jiraAcproSettingsService;
        this.permissionManager = permissionManager;
    }

    public boolean isHasPermission(HttpServletRequest request) {
        User user = (User) request.getSession().getAttribute(DefaultAuthenticator.LOGGED_IN_KEY);
        if (user != null) {
            return permissionManager.hasPermission(Permissions.ADMINISTER, user);
        }
        return false;
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        // Set to expire far in the past.
        response.setHeader("Expires", "Sat, 6 May 1995 12:00:00 GMT");
        // Set standard HTTP/1.1 no-cache headers.
        response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
        // Set IE extended HTTP/1.1 no-cache headers (use addHeader).
        response.addHeader("Cache-Control", "post-check=0, pre-check=0");
        // Set standard HTTP/1.0 no-cache header.
        response.setHeader("Pragma", "no-cache");        

        if (!isHasPermission(request)) {
            response.setStatus(HttpStatus.SC_NOT_FOUND);
            return;
        }

        if (request.getParameter(ACTION_SETTINGS) != null) {
            buildSettings(request, response);
            return;
        }

        try {
            JSONObject jsonObject = null;
            if (request.getParameter(ACTION_USERS) != null) {
                jsonObject = buildUsers();
            } else if (request.getParameter(ACTION_ISSUE_TYPES) != null) {
                jsonObject = buildIssueTypes();
            } else if (request.getParameter(ACTION_PRIORITIES) != null) {
                jsonObject = buildPriorities();
            } else if (request.getParameter(ACTION_STATUSES) != null) {
                jsonObject = buildStatuses();
            } else if (request.getParameter(ACTION_RESOLUTIONS) != null) {
                jsonObject = buildResolutions();
            } else if (request.getParameter(ACTION_PROJECT_COMPONENTS) != null) {
                Long projectId = Long.valueOf(request.getParameter(PARAM_PROJECT_ID));
                jsonObject = buildProjectComponents(projectId);
            } else if (request.getParameter(ACTION_PROJECT_VERSIONS) != null) {
                Long projectId = Long.valueOf(request.getParameter(PARAM_PROJECT_ID));
                jsonObject = buildProjectVersions(projectId);
            } else if (request.getParameter(ACTION_EVENTS) != null) {
                jsonObject = buildEvents(request);
            }
            writeJson(response, jsonObject);
            
        } catch (JSONException e) {
            //must not occur
            log.error("Error", e);
            throw new RuntimeException(e);
        }

    }

    private void writeJson(HttpServletResponse response, JSONObject jsonObject) throws IOException {
        response.setContentType(CONTENT_TYPE_JSON);
        PrintWriter out = response.getWriter();
        out.println(jsonObject.toString());
        out.flush();
    }

    private void buildSettings(HttpServletRequest request, HttpServletResponse response) throws IOException {
        Settings settings = (Settings) request.getSession().getAttribute(Constants.SETTINGS_SESSION_KEY);
        String xml = jiraAcproSettingsService.save(settings);
        response.setContentType(CONTENT_TYPE_XML);
        PrintWriter out = response.getWriter();
        out.write(xml);
        out.flush();
    }

    private JSONObject buildUsers() throws JSONException {
        List<JiraUser> jiraUsers = jiraAcproPluginJiraManager.getAllJiraUsers();
        JSONArray jsonArray = new JSONArray();
        for (JiraUser jiraUser: jiraUsers) {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("userName", jiraUser.getUserName());
            jsonObject.put("email", jiraUser.getEmail());
            jsonObject.put("fullName", jiraUser.getFullName());
            jsonArray.put(jsonObject);
        }
        JSONObject retValue = new JSONObject();
        retValue.put("users", jsonArray);
        return retValue;
    }

    private JSONObject buildIssueTypes() throws JSONException {
        List<JiraIssueType> jiraIssueTypes = jiraAcproPluginJiraManager.getJiraIssueTypes();
        JSONArray jsonArray = new JSONArray();
        for (JiraIssueType jiraIssueType: jiraIssueTypes) {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("id", jiraIssueType.getId());
            jsonObject.put("name", jiraIssueType.getName());
            jsonArray.put(jsonObject);
        }
        JSONObject retValue = new JSONObject();
        retValue.put("issueTypes", jsonArray);
        return retValue;
    }

    private JSONObject buildPriorities() throws JSONException {
        List<JiraPriority> jiraPriorities = jiraAcproPluginJiraManager.getJiraPriorities();
        JSONArray jsonArray = new JSONArray();
        for (JiraPriority jiraPriority: jiraPriorities) {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("id", jiraPriority.getId());
            jsonObject.put("name", jiraPriority.getName());
            jsonArray.put(jsonObject);
        }
        JSONObject retValue = new JSONObject();
        retValue.put("priorities", jsonArray);
        return retValue;
    }

    private JSONObject buildStatuses() throws JSONException {
        List<JiraStatus> jiraStatuses = jiraAcproPluginJiraManager.getJiraStatuses();
        JSONArray jsonArray = new JSONArray();
        for (JiraStatus jiraStatus: jiraStatuses) {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("id", jiraStatus.getId());
            jsonObject.put("name", jiraStatus.getName());
            jsonArray.put(jsonObject);
        }
        JSONObject retValue = new JSONObject();
        retValue.put("statuses", jsonArray);
        return retValue;
    }

    private JSONObject buildResolutions() throws JSONException {
        List<JiraResolution> jiraObjs = jiraAcproPluginJiraManager.getJiraResolutions();
        JSONArray jsonArray = new JSONArray();
        for (JiraResolution jiraObj: jiraObjs) {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("id", jiraObj.getId());
            jsonObject.put("name", jiraObj.getName());
            jsonArray.put(jsonObject);
        }
        JSONObject retValue = new JSONObject();
        retValue.put("resolutions", jsonArray);
        return retValue;
    }

    private JSONObject buildProjectComponents(Long projectId) throws JSONException {
        List<JiraProjectComponent> list = jiraAcproPluginJiraManager.getJiraProjectComponents(projectId);
        JSONArray jsonArray = new JSONArray();
        for (JiraProjectComponent item: list) {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("id", item.getId());
            jsonObject.put("name", item.getName());
            jsonArray.put(jsonObject);
        }
        JSONObject retValue = new JSONObject();
        retValue.put("projectComponents", jsonArray);
        return retValue;
    }

    private JSONObject buildProjectVersions(Long projectId) throws JSONException {
        List<JiraProjectVersion> list = jiraAcproPluginJiraManager.getJiraProjectVersions(projectId);
        JSONArray jsonArray = new JSONArray();
        for (JiraProjectVersion item: list) {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("id", item.getId());
            jsonObject.put("name", item.getName());
            jsonArray.put(jsonObject);
        }
        JSONObject retValue = new JSONObject();
        retValue.put("projectVersions", jsonArray);
        return retValue;
    }

    private JSONObject buildEvents(HttpServletRequest request) throws JSONException {
        Sync sync = (Sync) request.getSession().getAttribute(Constants.SESSION_SYNC_KEY);
        List<Event> list = sync.readEvents();
        JSONArray jsonArray = new JSONArray();
        for (Event item: list) {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("eventType", item.getEventType());
            jsonObject.put("message", item.getMessage());
            jsonObject.put("size", item.getSize());
            jsonArray.put(jsonObject);
        }
        JSONObject retValue = new JSONObject();
        retValue.put("progressEvents", jsonArray);
        return retValue;
    }

}
